package com.xhl.doeverything.service.impl;

import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xhl.doeverything.dao.UserDao;
import com.xhl.doeverything.dozer.DozerUtils;
import com.xhl.doeverything.dto.UserRequest;
import com.xhl.doeverything.entity.PageQueryCondition;
import com.xhl.doeverything.entity.PageQueryResult;
import com.xhl.doeverything.entity.UserDO;
import com.xhl.doeverything.es.constants.ElasticConstants;
import com.xhl.doeverything.es.index.IndexUser;
import com.xhl.doeverything.service.UserService;
import com.xhl.doeverything.utils.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author xionghuilong
 * @description: 用户服务
 * @date 2022/1/21 14:41
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Resource
    private DozerUtils dozer;

    @Resource
    private String userIndexName;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private JSONConfig jsonConfig;

    @Override
    public List<UserDO> queryUserList(UserRequest request) {
        log.info("入参-> {}",request);
//        List<UserDO> userList = this.userDao.selectList(new LambdaQueryWrapper<UserDO>().eq(UserDO::getName,request.getName()));
        List<UserDO> userList = this.userDao.selectList(new LambdaQueryWrapper<UserDO>().like(UserDO::getName,request.getName()));
        return userList;
    }

    @Override
    public int addUser(UserRequest request) {
        log.info("入参-> {}",request);
        UserDO userDO = this.dozer.map(request,UserDO.class);
        //数据入到mysql里
        int count = this.userDao.insert(userDO);

        //数据入到es里
        IndexUser user = this.dozer.map(userDO, IndexUser.class);
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index(this.userIndexName);
        String addUserStr = new JSONObject(user, JSONConfig.create()).toString();
        indexRequest.source(addUserStr, XContentType.JSON)
                .type(ElasticConstants.DEFAULT_TYPE)
                .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
                .id(String.valueOf(user.getId()));
        try {
            elasticsearchRestTemplate.getClient().index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return count;
    }

    @Override
    public int addUserWithIndex(UserRequest request) {
        log.info("入参-> {}",request);
        UserDO userDO = this.dozer.map(request,UserDO.class);
        //数据入到mysql里
        int count = this.userDao.insert(userDO);

        //数据入到es里
        IndexUser user = this.dozer.map(userDO, IndexUser.class);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        elasticsearchRestTemplate.index(new IndexQueryBuilder().withIndexName(this.userIndexName).withId(user.getId())
                .withObject(user).build());

        return count;
    }

    @Override
    public int updateUser(UserRequest request) {
        LambdaUpdateWrapper<UserDO> wrapper = new LambdaUpdateWrapper<UserDO>();
        wrapper.set(UserDO::getName,request.getName()).eq(UserDO::getId,request.getId());

        //更新mysql
        int count = this.userDao.update(new UserDO(),wrapper);

        //更新es
        IndexUser indexUser = elasticsearchRestTemplate.queryForObject(GetQuery.getById(request.getId()),IndexUser.class);
        indexUser.setName(request.getName());
        UpdateRequest updateRequest = new UpdateRequest();
        String updateStr = new JSONObject(indexUser, jsonConfig).toString();
        updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        updateRequest.doc(updateStr, XContentType.JSON);
        try {
            elasticsearchRestTemplate.update(new UpdateQueryBuilder().withIndexName(userIndexName)
                    .withId(request.getId()).withClass(IndexUser.class).withUpdateRequest(updateRequest).build());
        } catch (Exception e) {
            log.error("es用户数据更新失败",e);
        }

        return count;
    }

    @Override
    public int deleteUser(String name) {
        int count = this.userDao.delete(new LambdaQueryWrapper<UserDO>().like(UserDO:: getName,name));
        log.info("删除了" + count + "条记录！");
        // ES删除资源
        DeleteQuery deleteQuery = new DeleteQuery();
        BoolQueryBuilder bool = new BoolQueryBuilder();
        bool.must(QueryBuilders.matchQuery("name", name));
        deleteQuery.setIndex(userIndexName);
        deleteQuery.setQuery(bool);
        try {
            elasticsearchRestTemplate.delete(deleteQuery, IndexUser.class);
        } catch (Exception e) {
            log.error("es用户删除失败",e);
        }
        return count;
    }

    @Override
    public PageQueryResult<UserDO> queryPage(PageQueryCondition<UserRequest> request) {

        Page<UserRequest> page = PageUtil.transPageQueryCondition2MybatisPlusPage(request, dozer);
        IPage<UserDO> pageResult = this.userDao.queryPage(page, request.getModel());
//        IPage<UserDO> page = new Page(request.getCurrent(),request.getSize());
//        IPage<UserDO> pageResult = this.userDao.selectPage(page, new LambdaQueryWrapper<UserDO>().like(UserDO::getName,"122"));

//        return PageUtil.transMybatisPlusPage2PageQueryResult(pageResult,
//                dozer.mapList(pageResult.getRecords(), UserDO.class));
        return PageUtil.transMybatisPlusPage2PageQueryResult(pageResult,pageResult.getRecords());
    }

    @Override
    public PageQueryResult<UserDO> esQueryPage(PageQueryCondition<UserRequest> request) {

        UserRequest model = request.getModel();
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        boolQuery.must(QueryBuilders.matchQuery("name", model.getName()));
        boolQuery.must(QueryBuilders.termQuery("age", model.getAge()));
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withPageable(PageRequest.of((int) request.getCurrent() - 1, (int) request.getSize()))
//                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();
        log.debug("用户分页查询es参数：{}", searchQuery.getQuery().toString());
        AggregatedPage<IndexUser> result = elasticsearchRestTemplate.queryForPage(searchQuery, IndexUser.class);
        List<IndexUser> indexUsers = result.getContent();

        //组装返回值
        PageQueryResult<UserDO> ret = new PageQueryResult<>();
        ret.setCurrent((int) request.getCurrent());
        ret.setSize((int) request.getSize());
        ret.setTotal((int) result.getTotalElements());
        ret.setRecords(this.dozer.mapList(indexUsers,UserDO.class));

        return ret;

    }
}
